package light.im;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.atomic.AtomicInteger;
import org.json.JSONObject;
import light.network.Endpoint;
import light.network.EndpointSession;
import light.network.IEndpointHandler;
import light.network.SendHandler;
import light.network.UdpEndpoint;
import light.network.object.PackObject;

public class IMEndpoint implements IActionEndpoint {

	
	String host;
	int port;

	Endpoint udpServer = new UdpEndpoint();
	ActionDispather defaultDispatcher = new ActionDispather(this);
	
	public IMEndpoint(String host, int port) throws IOException
	{
		this.host = host;
		this.port = port;
	}
	
	@Override
	public IMEndpoint registerAction(IAction action)
	{
		defaultDispatcher.registerAction(action);
		return this;
	}

	@Override
	public IMEndpoint registerAction(String actionName, IAction action)
	{
		defaultDispatcher.registerAction(actionName, action);
		return this;
	}
	
	@Override
	public void start() throws IOException
	{
		udpServer.start(new InetSocketAddress(host, port));
		udpServer.setReceiveHandler(defaultDispatcher);
	}

	public void setDispatcher(IEndpointHandler handler) {
		udpServer.setReceiveHandler((IEndpointHandler) handler);
	}

	IMEndpoint self;
	
	@Override
	public void openSession(SocketAddress target, Object attachment, final IMSessionHandler handler) {
		udpServer.openSession(target, attachment, new SendHandler() {
			
			@Override
			public void onSession(EndpointSession session, Object attachment) {
				handler.onSession(new UdpIMSession(session, self), attachment);
			}
			@Override
			public void onFailed(Throwable exc, Object attachment) {
				handler.onFailed(exc, attachment);
			}
		});
	}

	/**
	 * 向服务端发送请求，当接收到应答时，会触发回调函数
	 * @param target
	 * @param req
	 * @param handler
	 */
	@Override
	public void request(SocketAddress target, final PackObject req, final IResponseHandler handler)
	{
		openSession(target, null, new IMSessionHandler() {
			@Override
			public void onSession(IMSession session, Object attachment) {
				try {
					Integer reqId = genRequestId();
					req.put(ActionDispather.RequestPackageKey, reqId);
					defaultDispatcher.registerResponse(reqId, handler);//System.out.println("ins1: "+defaultDispatcher+", "+defaultDispatcher.responseDispatcher.containsKey(reqId));
					session.write(req);
				} catch (IOException e) {
					onFailed(e, attachment);
				}
			}
			@Override
			public void onFailed(Throwable exc, Object attachment) {
				handler.onFail(exc);
			}
		});
	}
	
	
	private static AtomicInteger requestIdSequence = new AtomicInteger(0);
	/**
	 * 产生一个新的请求标识符，仅在本类的单一实例范围内有效
	 * @return
	 */
	private static Integer genRequestId()
	{
		return requestIdSequence.incrementAndGet();
	}


	
	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		IMEndpoint s = new IMEndpoint("localhost", 10606);
		s.registerAction("echo", new IAction() {
			
			@Override
			public void execute(IMSession session, PackObject req) {
				try {
					System.out.println("echo it, "+req.getHeader());
					session.write(req);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});
		s.start();
		
		runclient();
	}

	public static void runclient() throws Exception
	{
		JSONObject obj = new JSONObject().put("a", "haha").put("action", "echo").put("fttt", "haha");

		PackObject dat = new PackObject(obj);

		IMEndpoint client = new IMEndpoint("localhost", 10607);
		client.start();
		client.request(new InetSocketAddress("localhost", 10606), dat, new IResponseHandler() {
			@Override
			public void onSuccess(PackObject resp) {
				System.out.println("get resp: "+resp);
			}
			@Override
			public void onFail(Throwable t) {
				t.printStackTrace();
			}
		});
	}
}
